﻿using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using BES;

namespace BES.Tests
{
    [TestClass]
    public class GDAT_Tests
    {

        public const string FileName = "Test.xml";
        private GDAT<MockObject> Table;

        #region Utility Code

        [TestCleanup]
        public void Cleanup()
        {
            if ( File.Exists(FileName) )
                File.Delete(FileName);
        }

        private class MockObject
        {
            public string Name;
            public int Quantity;
            protected bool HiddenValue = true;
            public string Description { get; set; }
            protected float Prrcentage { get; set; }
        }

        #endregion

        #region File IO Tests

        [TestMethod]
        public void GDAT_Save()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Banana", Quantity = 1 });
            table.Save(FileName);
            Assert.IsTrue(File.Exists(FileName), "Save file exists.");
        }

        [TestMethod]
        public void GDAT_Load()
        {
            var table1 = new GDAT<MockObject>();
            table1.Insert(new MockObject() { Name = "Pineapple", Quantity = 1 });
            table1.Save(FileName);
            var table2 = new GDAT<MockObject>();
            table2.Load(FileName);
            Assert.IsTrue(table2.Count == 1, "Loading file populates Table.");
        }

        [TestMethod]
        public void GDAT_Load_Null()
        {
            var table = new GDAT<MockObject>();
            table.Load("DOESNOTEXIST");
            Assert.IsTrue(table.Count == 0, "Loading null file clears Table.");
        }

        [TestMethod]
        public void GDAT_Load_Empty()
        {
            var table = new GDAT<MockObject>();
            table.Clear();
            table.Save(FileName);
            table.Load(FileName);
            Assert.IsTrue(table.Count == 0, "Loading empty file does not error.");
        }

        #endregion

        #region Public Field Only Tests

        [TestMethod]
        public void GDAT_Select_Single_1()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            var res = table.Select((t) => t.Name.Equals("Mock"));
            Assert.IsTrue(res.Count == 1, "1 Value returned");
            Assert.IsTrue(res[0].Name.Equals("Mock"), "Name matches.");
            Assert.IsTrue(res[0].Quantity == 1, "Quantity matches.");
        }

        [TestMethod]
        public void GDAT_Select_Single_2()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Fake", Quantity = 2 });
            table.Insert(new MockObject() { Name = "Lump", Quantity = 3 });
            var res = table.Select((t) => t.Name.Equals("Fake"));
            Assert.IsTrue(res.Count == 1, "1 Value returned");
            Assert.IsTrue(res[0].Name.Equals("Fake"), "Name matches.");
            Assert.IsTrue(res[0].Quantity == 2, "Quantity matches.");
        }

        [TestMethod]
        public void GDAT_Select_Multiple()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Fake", Quantity = 2 });
            table.Insert(new MockObject() { Name = "Lump", Quantity = 3 });
            var res = table.Select((t) => t.Quantity > 1);
            Assert.IsTrue(res.Count == 2, "2 objects returned");
        }

        [TestMethod]
        public void GDAT_Select_None()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Fake", Quantity = 2 });
            table.Insert(new MockObject() { Name = "Lump", Quantity = 3 });
            var res = table.Select((t) => t.Quantity < 1);
            Assert.IsTrue(res.Count == 0, "No objects returned");
        }

        [TestMethod]
        public void GDAT_Insert()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            var obj = new MockObject() { Name = "Tester", Quantity = 999 };
            var count = table.Count;
            table.Insert(obj);
            Assert.IsTrue(table.Count == count + 1, "Table sized incremented");
        }

        [TestMethod]
        public void GDAT_Update_Single_1()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            var count = table.Count;
            table.Update((t) => t.Name.Equals("Mock"), (t) => { t.Quantity = 12345; return t; });
            Assert.IsTrue(table.Count == count, "Table size did not change");
            var res = table.Select((t) => t.Name.Equals("Mock"));
            Assert.IsTrue(res.Count == 1, "Test field exists.");
            Assert.IsTrue(res[0].Quantity == 12345, "Test field was updated");
        }

        [TestMethod]
        public void GDAT_Update_Single_2()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            var count = table.Count;
            table.Update((t) => t.Name.Equals("Mock"), (t) => { t.Quantity = 12345; return t; });
            Assert.IsTrue(table.Count == count, "Table size did not change");
            var res = table.Select((t) => t.Name.Equals("Mock"));
            Assert.IsTrue(res.Count == 1, "Test field exists.");
            Assert.IsTrue(res[0].Quantity == 12345, "Test field was updated");
        }

        [TestMethod]
        public void GDAT_Update_Multiple()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Mock", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Fake", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Bad", Quantity = 5 });
            table.Insert(new MockObject() { Name = "Egg", Quantity = 6 });
            var count = table.Count;
            table.Update(t => t.Quantity == 1, t => new MockObject() { Name = t.Name + "Single", Quantity = t.Quantity });
            Assert.IsTrue(table.Count == count, "Table size did not change");
            var res2 = table.Select((t) => t.Quantity == 1);
            foreach ( var obj in res2 )
            {
                Assert.IsTrue(obj.Name.EndsWith("Single"), "Test field was updated");
            }
        }

        [TestMethod]
        public void GDAT_Remove_Single()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Apple", Quantity = 1 });
            var count = table.Count;
            table.Remove((t) => t.Name.Equals("Apple"));
            Assert.IsTrue(count - 1 == table.Count, "Table size reduced by 1");
        }

        [TestMethod]
        public void GDAT_Remove_None()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Orange", Quantity = 1 });
            var count = table.Count;
            table.Remove((t) => t.Name.Equals("Apple"));
            Assert.IsTrue(count == table.Count, "Table size not reduced");
        }

        [TestMethod]
        public void GDAT_Remove_Multiple()
        {
            var table = new GDAT<MockObject>();
            table.Insert(new MockObject() { Name = "Orange", Quantity = 2 });
            table.Insert(new MockObject() { Name = "Apple", Quantity = 1 });
            table.Insert(new MockObject() { Name = "Applesauce", Quantity = 3 });
            var count = table.Count;
            table.Remove((t) => t.Name.StartsWith("Apple"));
            Assert.IsTrue(count - 2 == table.Count, "Table size not reduced");
        }

        #endregion

    }
}
